package com.yzs.base.base

import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.*
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gyf.immersionbar.ImmersionBar


/**
 * author : yzs
 * time   : 2021/07/08
 * desc   : 基础类封装
 */
abstract class BaseDialogFragment() : DialogFragment() {

    constructor(cancelable: Boolean = true) : this() {
        _canceledOnTouchOutside = cancelable
    }

    private val TAG = "BaseDialogFragment"
    open fun before() {}
    abstract fun getLayoutId(): Int
    abstract fun init(view: View, savedInstanceState: Bundle?)

    lateinit var mContent: Context
    private var _canceledOnTouchOutside: Boolean = true // 禁止外部触摸取消
    var _animRes: Int = -1          // 动画
    var _width: Int = -1            // dialog 的宽
    var _height: Int = -1           // dialog 的高
    var _dimAmount: Float = 0.5f    // dialog 蒙版透明度
    var _gravity: Int = Gravity.CENTER  // dialog 的方向
    var _widthFull: Boolean = false     // 是否宽度占满 优先于 _width
    var _isFull: Boolean = false        // 是否全屏占满
    var _isCanBack: Boolean = true      // 是否点击关闭

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initViewModel()
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val d = super.onCreateDialog(savedInstanceState)
        d.setCancelable(_canceledOnTouchOutside)
        d.setCanceledOnTouchOutside(_canceledOnTouchOutside)
        d.setOnKeyListener { dialog, keyCode, event ->
            if (!_canceledOnTouchOutside) keyCode == KeyEvent.KEYCODE_BACK
            else false
        }
        return d
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(getLayoutId(), container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        init(view, savedInstanceState)
        observe()
        onClick()
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        mContent = context
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        // 处理状态栏变黑
        ImmersionBar.with(this).init()
    }

    /**
     * 初始化viewModel
     * 之所以没有设计为抽象，是因为部分简单activity可能不需要viewModel
     * observe同理
     */
    open fun initViewModel() {}

    /**
     * 注册观察者 需要把 MChatActivity 传入获取 VM 绑定 ac 声明周期
     */
    open fun observe() {}

    /**
     * 点击事件
     */
    open fun onClick() {}

    /**
     * 通过 activity 获取 viewModel，跟随 activity 生命周期
     */
    fun <T : ViewModel> getActivityViewModel(modelClass: Class<T>): T {
        return ViewModelProvider(requireActivity().viewModelStore, defaultViewModelProviderFactory).get(modelClass)
    }

    /**
     * 通过 fragment 获取 viewModel，跟随 fragment 生命周期
     */
    protected open fun <T : ViewModel> getFragmentViewModel(modelClass: Class<T>): T {
        return ViewModelProvider(this, defaultViewModelProviderFactory).get(modelClass)
    }

    /**
     * 扩展用于liveData便捷写法的函数
     * [block] liveData 对象，响应 change 变化的逻辑块
     */
    protected inline fun <T : Any> LiveData<T?>.observeKt(crossinline block: (T?) -> Unit) {
        this.observe(this@BaseDialogFragment, Observer { block(it) })
    }

    /**
     * 扩展用于 liveData 便捷写法的函数
     * [block] liveData 对象，响应 change 变化的逻辑块
     * 认为 不为 null 的情况
     */
    protected inline fun <T : Any> LiveData<T>.observeKtNoNull(crossinline block: (T) -> Unit) {
        this.observe(this@BaseDialogFragment, Observer { block(it) })
    }

    override fun onStart() {
        super.onStart()
        before()
        val dialog = dialog ?: return
        val window = dialog.window ?: return
        val params = window.attributes
        // 设置背景色透明
        window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        // 设置Dialog动画效果
        if (_animRes > 0) window.setWindowAnimations(_animRes)
        // 设置Dialog的宽度
        if (_width > 0) params.width = _width
        // 设置Dialog的高度
        if (_height > 0) params.height = _height
        if (_widthFull) params.width = ViewGroup.LayoutParams.MATCH_PARENT
        if (_isFull) {
            params.width = ViewGroup.LayoutParams.MATCH_PARENT
            params.height = ViewGroup.LayoutParams.MATCH_PARENT
        }

        // 设置屏幕透明度 0.0f~1.0f(完全透明~完全不透明)
        params.dimAmount = _dimAmount
        params.gravity = _gravity
        window.attributes = params
        isCancelable = _isCanBack
    }

    fun show(manager: FragmentManager) {
        if (isAdded) {
            return
        }
        if (isVisible) {
            return
        }
        try {
            super.show(manager, TAG)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * https://www.jianshu.com/p/bcc5af0085d3?t=1481296807683
     *
     * https://blog.csdn.net/ranxiedao/article/details/8214936
     */
    fun showAllowingStateLoss(manager: FragmentManager) {
        try {
            val dismissed = DialogFragment::class.java.getDeclaredField("mDismissed")
            dismissed.isAccessible = true
            dismissed.set(this, false)
        } catch (e: NoSuchFieldException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        }
        try {
            val shown = DialogFragment::class.java.getDeclaredField("mShownByMe")
            shown.isAccessible = true
            shown.set(this, true)
        } catch (e: NoSuchFieldException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        }
        val ft = manager.beginTransaction()
        ft.add(this, TAG)
        ft.commitAllowingStateLoss()
    }

    override fun dismiss() {
        try {
            super.dismissAllowingStateLoss()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}